package componentes.basicos;

import java.util.ArrayList;

/**
 * Esta classe representa uma Unidade de Controle Principal.
 * A unidade controle principal é responsável por mandar sinais de 
 * controle para determinados dispositivos, permitindo ou não que 
 * tais dispositivos possam ou não realizar suas respectivas tarefas.
 * 
 * @author Gustavo Miguel, Cleisson Alves, Evandro Francisco, Lucas.
 */
public class UnidadeControlePrincipal {
    
    // Atributos da classe
    // Barramento por onde são enviados os sinais de controle.
    private Barramento escreveMem;      // Sinal de controle para indicar uma escrita na memoria
    private Barramento escreveReg;      // Sinal de controle para indicar uma escrita em um registrador no banco de registradores.
    private Barramento escrevePC;       // Sinal de controle para indicar uma selecao no PC.
    private Barramento leMemoria;       // Sinal de controle para indicar uma leitura na memoria de dados.
    private Barramento memParaReg;      // Sinal de controle para indicar que um dado lido na memoria de dados devera ser escrito em um registrador no bando de registradores.   
    private Barramento regDestino;      // Sinal de controle para indicar qual registrador ira ser Escrito no registrador de destino no banco de registradores.
    private Barramento opALU;           // Sinal de controle que indica qual sinal de operacao deve ser enviado para ALU.
    private Barramento origemALUA;       // Sinal de controle que indica qual a segunda entrada da ALU.
    private Barramento origemALUB;
    private Barramento iOuD;
    private Barramento origemPC;
    private Barramento escreveIR;
    private Barramento escrevePCCond;
    
    public UnidadeControlePrincipal() {
        
        this.escreveMem = new Barramento(Constantes.INOPERANTE);
        this.escreveReg = new Barramento(Constantes.INOPERANTE);
        this.escrevePC = new Barramento(Constantes.OPERANTE);
        this.leMemoria = new Barramento(Constantes.OPERANTE);
        this.memParaReg = new Barramento(Constantes.INOPERANTE);
        this.regDestino = new Barramento(Constantes.INOPERANTE);
        this.opALU = new Barramento(Constantes.INOPERANTE);
        this.origemALUA = new Barramento(Constantes.INOPERANTE);
        this.origemALUB = new Barramento(Constantes.INOPERANTE);
        this.escrevePCCond = new Barramento(Constantes.INOPERANTE);
        this.iOuD = new Barramento(Constantes.INOPERANTE);
        this.origemPC = new Barramento(Constantes.INOPERANTE);
        this.escreveIR = new Barramento(Constantes.OPERANTE);
    
    
        
    }
    
    /**
     * Cria uma unidade de Controle a partir de um tipo de instrução.
     * Se o tipo for R, então os sinais de controle da unidade são 
     * configurados a partir de uma intrução R. Outros tipos podem 
     * ser: lw, sw, beq e j.
     * @see Barramento
     * @see ALU
     */
    public UnidadeControlePrincipal(String tipo) {
        setSinais(tipo);
    }

    /**
     * Retorna o Barramento correspondente ao sinal que indica uma escrita na
     * memória. Um sinal operante desse Barramento significa que uma escrita
     * na memória pode ser realizada
     * @return Barramento correspondente ao sinal de escrita na memória.
     */
    public Barramento getEscreveMem() {
        return escreveMem;
    }

    /**
     * Retorna o Barramento correspondente ao sinal que indica uma escrita no
     * registrador de destino. Um sinal operante desse Barramento significa 
     * uma escrita no registrador de destino.
     * @see Registrador.
     * @return Barramento correspondente ao sinal de escrita no registrador de
     * destino.
     */
    public Barramento getEscreveReg() {
        return escreveReg;
    }

    /**
     * Retorna o Barramento que corresponde ao sinal que inidica a leitura na
     * em uma memória. Um sinal operante desse Barramento permite uma leitura
     * na memória.
     * @return Barramento correspondente ao sinal de leitura na memória.
     */
    public Barramento getLeMemoria() {
        return leMemoria;
    }

    /**
     * Retorna o Barramento correspondente ao sinal que indica se um determinado
     * (Palavra) da memória será escrita no registrador de destino. Um sinal
     * operante desse Barramento permite que um dado vindo da memória possa ser
     * escrita no registrador.
     * @return Barramento que indica um sinal de escrita do dado da memória para
     * o registrador.
     */
    public Barramento getMemParaReg() {
        return memParaReg;
    }

    /**
     * Retorna um Barramento correspondente ao sinal de operação da ALU. Esse
     * sinal pode ser enviado até a ALU para indicar uma operação a ser feita.
     * @return Barramento de sinal de operação da ALU.
     */
    public Barramento getOpALU() {
        return opALU;
    }

   

    /**
     * Retorna o Barramento correspondente ao sinal que indica que haverá uma 
     * escrita no registrador de destino. Um sinal operante desse barramento 
     * indica que o registrador de destino receberá um determinado valor.
     * @return Barramento que indica que uma escrita no registrador de destino.
     */
    public Barramento getRegDestino() {
        return regDestino;
    }

    /**
     * Retorna o Barramento que permite selecionar uma entrada para o contador
     * de programa. 
     * @return Barramento que indica um sinal de escrita no PC.
     */
    public Barramento getEscrevePC() {
        return escrevePC;
    }
    
    public Barramento getOrigemALUA() {
        return origemALUA;
    }
    
   public Barramento getOrigemALUB() {
        return origemALUB;
    }
   public Barramento getEscrevePCCond() {
        return escrevePCCond;
    }
    public Barramento getIOuD() {
        return iOuD;
    }
    public Barramento getOrigemPC() {
        return origemPC;
    }
    
    public Barramento getEscreveIR() {
        return escreveIR;
    }
        
       
     /**
     * Método para configura os sinais de entradas de uma unidade de controle. 
     * De acordo com um tipo de sinal, os Barramentos de sinais são configurados
     * como operantes e não operantes.
     * @param tipo Tipo que corresponde ao tipo da instrução, podendo ser:
     * R, J, LW, SW, BEQ.
     */
    public void setSinais(String tipo) {
        if(tipo.equals("R")) {
            this.escreveMem = new Barramento(Constantes.INOPERANTE);
            this.escreveReg = new Barramento(Constantes.OPERANTE);
            this.escrevePC = new Barramento(Constantes.INOPERANTE);
            this.leMemoria = new Barramento(Constantes.INOPERANTE);
            this.memParaReg = new Barramento(Constantes.INOPERANTE);
            this.regDestino = new Barramento(Constantes.OPERANTE);
            this.opALU = new Barramento(Constantes.DOIS);
            this.origemALUA = new Barramento(Constantes.OPERANTE);
            this.origemALUB = new Barramento(Constantes.INOPERANTE);
            this.escrevePCCond = new Barramento(Constantes.INOPERANTE);
            this.iOuD = new Barramento(Constantes.INOPERANTE);
            this.origemPC = new Barramento(Constantes.INOPERANTE);
            this.escreveIR = new Barramento(Constantes.OPERANTE);
            
           
        } 
        else if (tipo.equals("J")) { 
            this.escreveMem = new Barramento(Constantes.INOPERANTE);
            this.escreveReg = new Barramento(Constantes.INOPERANTE);
            this.escrevePC = new Barramento(Constantes.OPERANTE);
            this.leMemoria = new Barramento(Constantes.INOPERANTE);
            this.memParaReg = new Barramento(Constantes.INOPERANTE);
            this.regDestino = new Barramento(Constantes.INOPERANTE);
            this.opALU = new Barramento(Constantes.INOPERANTE);
            this.origemALUA = new Barramento(Constantes.INOPERANTE);
            this.origemALUB = new Barramento(Constantes.INOPERANTE);
            this.escrevePCCond = new Barramento(Constantes.INOPERANTE);
            this.iOuD = new Barramento(Constantes.INOPERANTE);
            this.origemPC = new Barramento(Constantes.DOIS);
            this.escreveIR = new Barramento(Constantes.INOPERANTE);
            
        } 
        else if (tipo.equals("BEQ")) {
            this.escreveMem = new Barramento(Constantes.INOPERANTE);
            this.escreveReg = new Barramento(Constantes.INOPERANTE);
            this.escrevePC = new Barramento(Constantes.INOPERANTE);
            this.leMemoria = new Barramento(Constantes.INOPERANTE);
            this.memParaReg = new Barramento(Constantes.INOPERANTE);
            this.regDestino = new Barramento(Constantes.INOPERANTE);
            this.opALU = new Barramento(Constantes.OPERANTE);
            this.origemALUA = new Barramento(Constantes.OPERANTE);
            this.origemALUB = new Barramento(Constantes.TRES);
            this.escrevePCCond = new Barramento(Constantes.OPERANTE);
            this.iOuD = new Barramento(Constantes.INOPERANTE);
            this.origemPC = new Barramento(Constantes.OPERANTE);
            this.escreveIR = new Barramento(Constantes.INOPERANTE);
            
                       
        }  
        else if (tipo.equals("LW")) {
            this.escreveMem = new Barramento(Constantes.INOPERANTE);
            this.escreveReg = new Barramento(Constantes.OPERANTE);
            this.escrevePC = new Barramento(Constantes.INOPERANTE);
            this.leMemoria = new Barramento(Constantes.OPERANTE);
            this.memParaReg = new Barramento(Constantes.OPERANTE);
            this.regDestino = new Barramento(Constantes.INOPERANTE);
            this.opALU = new Barramento(Constantes.INOPERANTE);
            this.origemALUA = new Barramento(Constantes.OPERANTE);
            this.origemALUB = new Barramento(Constantes.DOIS);
            this.escrevePCCond = new Barramento(Constantes.INOPERANTE);
            this.iOuD = new Barramento(Constantes.OPERANTE);
            this.origemPC = new Barramento(Constantes.INOPERANTE);
            this.escreveIR = new Barramento(Constantes.OPERANTE);
                     
        }  
        else if (tipo.equals("SW")) {
            this.escreveMem = new Barramento(Constantes.OPERANTE);
            this.escreveReg = new Barramento(Constantes.INOPERANTE);
            this.escrevePC = new Barramento(Constantes.INOPERANTE);
            this.leMemoria = new Barramento(Constantes.INOPERANTE);
            this.memParaReg = new Barramento(Constantes.INOPERANTE);
            this.regDestino = new Barramento(Constantes.INOPERANTE);
            this.opALU = new Barramento(Constantes.INOPERANTE);
            this.origemALUA = new Barramento(Constantes.OPERANTE);
            this.origemALUB = new Barramento(Constantes.DOIS);
            this.escrevePCCond = new Barramento(Constantes.INOPERANTE);
            this.iOuD = new Barramento(Constantes.OPERANTE);
            this.origemPC = new Barramento(Constantes.INOPERANTE);
            this.escreveIR = new Barramento(Constantes.INOPERANTE);            
        }
    }
    
} // Fim da classe.
